òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/14203

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

# 뺯
from jqdata import *

# 20ֵ   迼ƽ
# 5%
#Ӳ 0.5N
#ֹ 2N

## ʼ趨׼ȵ
def initialize(context):

## ===============================ѡ============================
    g.symbol='CU'
    set_benchmark(get_future_code(g.symbol)) 
    # set_option('futures_margin_rate', 0.06)
## ================ãǷԼƲ֣Ƶ===================
    g.shift=True                        # ǷкԼƲ
    g.frequency='1m'                    #ע⡿ӻز'1m',ز'1d'
    
# 趨˻Ϊ˻
    set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='index_futures')])
    set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023,close_today_commission=0.0023), type='index_futures')
    set_slippage(FixedSlippage(0))
    set_option('use_real_price', True)  # ̬Ȩģʽ(ʵ۸)
    log.set_level('order', 'error')     # ˵orderϵAPIıerror͵log

    g.N=20                     #ͨ
    g.limit=4                  #4β
    g.position=0               #ͷ
    g.add=0                    #Ӳִ
    g.lastprice=0              #һγɽ۸
    g.markprice=0              #¼޼۸
    g.lastfuture=None
    g.contract_change=False

    run_daily(before_market_open, time='before_open', reference_security=get_future_code(g.symbol))
    run_daily(while_open, time='every_bar', reference_security=get_future_code(g.symbol))    
    
## ǰк
def before_market_open(context):
# õԼ
    g.future=get_dominant_future(g.symbol)
    price=attribute_history(g.future,g.N+1,'1d',('open','high','low','close'))
    g.upperbound=max(price['high'].iloc[1:].dropna())  #ԼµģԼʱȡݲ20졣
    g.lowerbound=min(price['low'].iloc[1:].dropna())
    g.ATR=calc_ATR(price)

    if g.lastfuture==None:
        g.lastfuture=g.future
    elif g.lastfuture!=g.future:
        g.contract_change=True
        p1=get_bars(g.future,1,'1d','close')
        p0=get_bars(g.lastfuture,1,'1d','close')
        g.adj=p1[0][0]/p0[0][0]       #ڻ⣬ڵg.markprice
        
## ʱк
def while_open(context):

##-----------------------------Լ䶯-------------------------    
    if g.contract_change:
        if g.position<0:
            quantity=context.portfolio.short_positions[g.lastfuture].total_amount
            order_target(g.lastfuture,0,side='short')
            print('ԼƽԭԼ %s Ŀղ %d ' % (g.lastfuture, quantity))
            if g.shift:
                order(g.future,quantity,side='short')
                print('ԼºԼ %s ԭԼĿղ %d ' % (g.future, quantity))
                g.markprice=g.markprice*g.adj   #¼޼۸
        elif g.position>0:
            quantity=context.portfolio.long_positions[g.lastfuture].total_amount
            order_target(g.lastfuture,0,side='long')
            print('ԼƽԭԼ %s Ķ %d ' % (g.lastfuture, quantity))
            if g.shift:
                order(g.future,quantity,side='long')
                print('ԼºԼ %s ԭԼĶ %d ' % (g.future, quantity))
                g.markprice=g.markprice*g.adj   #¼޼۸
         
        # ƲֵĻҪreset  
        if g.shift==False:
            g.position=0                    #ͷ
            g.add=0                         #Ӳִ
            g.lastprice=0                   #һγɽ۸
        
        # һκԼ
        g.lastfuture=g.future
        g.contract_change=False
    
## ---------------------------------ȡǰ۸----------------------------------
    price=history(1,g.frequency,'close',g.future)
    #print(price)
    price=price.values[0][0]
    
## -----------------------------------ͻƿ-----------------------------------------
    #ͻưͨ
    breaksignal=check_break(price)
    
    if breaksignal=='long' and g.position<=0:    #ͻͨ޶֣ô֡
       if g.position<0:
           quantity=context.portfolio.short_positions[g.future].total_amount
           order_target(g.future,0,side='short')
           print('ͻƿ֡ǰƽԭ %s Ŀղ %d ' % (g.future,quantity))
           reset() 
       # 
       if g.position==0:
           unit = round(get_unit(context.portfolio.total_value,g.ATR,g.symbol))
           order(g.future,unit,side='long')
           print('ͻƿ֡ͻͨ %s %d ' % (g.future,unit))
           g.lastprice=price
           g.markprice=price
           g.add+=1
           g.position+=1
           
    if breaksignal=='short' and g.position>=0:    #ͻͨ޿ղ֣ôղ֡  
        if g.position>0:
           quantity=context.portfolio.long_positions[g.future].total_amount
           order_target(g.future,0,side='long')
           print('ͻƿ֡ղǰƽԭ %s Ķ %d ' % (g.future,quantity))
           reset()
        # ղ 
        if g.position==0:
           unit = round(get_unit(context.portfolio.total_value,g.ATR,g.symbol))
           order(g.future,unit,side='short')
           print('ͻƿ֡ͻͨղ %s %d ' % (g.future,unit))
           g.lastprice=price
           g.markprice=price
           g.add+=1
           g.position-=1
           
## -----------------------------жǷӲֹֻ--------------------------------
    # гֲ֣¼Ӳź
    if g.position!=0:
        ac_signal=add_or_close(price,g.lastprice,g.ATR,g.position)
    
        # źŲ   
        if ac_signal=='longclose':
            quantity=context.portfolio.long_positions[g.future].total_amount
            order_target(g.future,0,side='long')
            print('صֹƽ %s %d ֹ' % (g.future,quantity))
            reset()
        elif ac_signal=='shortclose':
            quantity=context.portfolio.short_positions[g.future].total_amount
            order_target(g.future,0,side='short')
            print('صֹƽղ %s %d ֹ' % (g.future,quantity))
            reset()
        elif ac_signal=='longadd' and g.add<g.limit:
            unit=round(get_unit(context.portfolio.total_value,g.ATR,g.symbol))
            order(g.future,unit,side='long')
            print('˳ƼӲ֡Ӷ %s %d' % (g.future,unit))
            g.lastprice=price
            g.add+=1
            g.position+=1
        elif ac_signal=='shortadd' and g.add<g.limit:
            unit=round(get_unit(context.portfolio.total_value,g.ATR,g.symbol))
            order(g.future,unit,side='short')
            print('˳ƼӲ֡ӿղ %s %d' % (g.future,unit))
            g.lastprice=price
            g.add+=1
            g.position-=1
# ---------------------------------ֹӯֹ-----------------------------------
    if g.position!=0:
        set_markprice(price)
        
        if check_stop(price):
            if g.position>0:
                quantity=context.portfolio.long_positions[g.future].total_amount
                order_target(g.future,0,side='long')
                print('ֹӯֹƽ %s %d ֽ' %(g.future,quantity))
            if g.position<0:
                quantity=context.portfolio.short_positions[g.future].total_amount
                order_target(g.future,0,side='short')
                print('ֹӯֹƽղ%s %d ֽ' %(g.future,quantity))
            reset()

def check_stop(price):
    if (g.position<0 and price>=1.05*g.markprice) or (g.position>0 and price<=0.95*g.markprice):
        return True
    return False

def set_markprice(price):
    if g.position<0:
        g.markprice=min(price,g.markprice)
    if g.position>0:
        g.markprice=max(price,g.markprice)

def add_or_close(price,lastprice,ATR,position):
    
    if position>0:   #жͷͷ
       if price>=lastprice+0.5*ATR:  #ͷӲ
            return 'longadd'
       if price<=lastprice-2*ATR:    #ͷƽ
            return 'longclose'
    if position<0:                   #пͷͷ
       if price<=lastprice-0.5*ATR:  #ͷӲ
            return 'shortadd'
       if price>=lastprice+2*ATR:    #ͷƽ
            return 'shortclose'
            
    return 0  #ɶûϴϴ˯

def check_break(price):
    if price>=g.upperbound:
        breaksignal='long'
    elif price<=g.lowerbound:
        breaksignal='short'
    else:
        breaksignal=0
    return breaksignal

def calc_ATR(price):
    T=len(price)-1
    ATR_list=[]
    for i in range(T+1):
        hml=price['high'].iloc[i]-price['low'].iloc[i]
        hmc=abs(price['high'].iloc[i]-price['close'].iloc[i-1])
        lmc=abs(price['low'].iloc[i]-price['close'].iloc[i-1])
        ATR_i=max(hml,hmc,lmc)
        ATR_list.append(ATR_i)
    ATR=mean(np.array(ATR_list))
    return ATR    

def get_unit(cash,ATR,symbol):
    future_coef_list = {'A':10, 'AG':15, 'AL':5, 'AU':1000,
                        'B':10, 'BB':500, 'BU':10, 'C':10, 
                        'CF':5, 'CS':10, 'CU':5, 'ER':10, 
                        'FB':500, 'FG':20, 'FU':50, 'GN':10, 
                        'HC':10, 'I':100, 'IC':1, 'IF':300, 
                        'IH':1, 'J':100, 'JD':5, 'JM':60, 
                        'JR':20, 'L':5, 'LR':10, 'M':10, 
                        'MA':10, 'ME':10, 'NI':1, 'OI':10, 
                        'P':10, 'PB':5, 'PM':50, 'PP':5, 
                        'RB':10, 'RI':20, 'RM':10, 'RO':10, 
                        'RS':10, 'RU':10, 'SF':5, 'SM':5, 
                        'SN':1, 'SR':10, 'T':10000, 'TA':5, 
                        'TC':100, 'TF':10000, 'V':5, 'WH':20, 
                        'WR':10, 'WS':50, 'WT':10, 'Y':10, 
                        'ZC':100, 'ZN':5}
    return (cash*0.01/ATR)/future_coef_list[symbol]

def reset():
    g.position=0    #ͷ
    g.add=0         #Ӳִ
    g.lastprice=0   #һγɽ۸
    g.markprice=0  #¼޼۸
    
########################## ȡڻԼϢ뱣 #################################
# ȡʱڽ׵ڻԼ
def get_future_code(symbol):
    future_code_list = {'A':'A9999.XDCE', 'AG':'AG9999.XSGE', 'AL':'AL9999.XSGE', 'AU':'AU9999.XSGE',
                        'B':'B9999.XDCE', 'BB':'BB9999.XDCE', 'BU':'BU9999.XSGE', 'C':'C9999.XDCE', 
                        'CF':'CF9999.XZCE', 'CS':'CS9999.XDCE', 'CU':'CU9999.XSGE', 'ER':'ER9999.XZCE', 
                        'FB':'FB9999.XDCE', 'FG':'FG9999.XZCE', 'FU':'FU9999.XSGE', 'GN':'GN9999.XZCE', 
                        'HC':'HC9999.XSGE', 'I':'I9999.XDCE', 'IC':'IC9999.CCFX', 'IF':'IF9999.CCFX', 
                        'IH':'IH9999.CCFX', 'J':'J9999.XDCE', 'JD':'JD9999.XDCE', 'JM':'JM9999.XDCE', 
                        'JR':'JR9999.XZCE', 'L':'L9999.XDCE', 'LR':'LR9999.XZCE', 'M':'M9999.XDCE', 
                        'MA':'MA9999.XZCE', 'ME':'ME9999.XZCE', 'NI':'NI9999.XSGE', 'OI':'OI9999.XZCE', 
                        'P':'P9999.XDCE', 'PB':'PB9999.XSGE', 'PM':'PM9999.XZCE', 'PP':'PP9999.XDCE', 
                        'RB':'RB9999.XSGE', 'RI':'RI9999.XZCE', 'RM':'RM9999.XZCE', 'RO':'RO9999.XZCE', 
                        'RS':'RS9999.XZCE', 'RU':'RU9999.XSGE', 'SF':'SF9999.XZCE', 'SM':'SM9999.XZCE', 
                        'SN':'SN9999.XSGE', 'SR':'SR9999.XZCE', 'T':'T9999.CCFX', 'TA':'TA9999.XZCE', 
                        'TC':'TC9999.XZCE', 'TF':'TF9999.CCFX', 'V':'V9999.XDCE', 'WH':'WH9999.XZCE', 
                        'WR':'WR9999.XSGE', 'WS':'WS9999.XZCE', 'WT':'WT9999.XZCE', 'Y':'Y9999.XDCE', 
                        'ZC':'ZC9999.XZCE', 'ZN':'ZN9999.XSGE','IH':'000016.XSHG','IF':'000300.XSHG','IC':'000905.XSHG'}
    try:
        return future_code_list[symbol]
    except:
        return 'WARNING: ޴˺Լ'
     